package com.youthburin.rmp.services.impl;

import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.BeanPropertyValueEqualsPredicate;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.comparators.ReverseComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.youthburin.base.services.AbstractService;
import com.youthburin.base.springjpa.MyRepository;
import com.youthburin.rmp.domain.RmpPermission;
import com.youthburin.rmp.domain.RmpPermissionGroup;
import com.youthburin.rmp.domain.RmpRole;
import com.youthburin.rmp.domain.RmpUser;
import com.youthburin.rmp.repositories.RmpPermissionGroupRepository;
import com.youthburin.rmp.repositories.RmpPermissionRepository;
import com.youthburin.rmp.repositories.RmpRoleRepository;
import com.youthburin.rmp.repositories.RmpUserRepository;
import com.youthburin.rmp.services.RmpRoleService;
import com.youthburin.rmp.shiro.MyShiroDbRealm;

@Service
public class RmpRoleServiceImpl extends AbstractService<RmpRole, String> implements RmpRoleService {
	@Autowired
	private RmpRoleRepository rmpRoleRepository;
	@Autowired
	private RmpPermissionRepository rmpPermissionRepository;
	@Autowired
	private RmpPermissionGroupRepository rmpPermissionGroupRepository;
	@Autowired
	private RmpUserRepository rmpUserRepository;
	@Autowired
	@Qualifier("shiroDbRealm")
	private MyShiroDbRealm myShiroDbRealm;

	@Override
	public MyRepository<RmpRole, String> getMyRepository() {
		return rmpRoleRepository;
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
	public RmpRole get(String id) {
		RmpRole role = super.get(id);
		// 设置权限
		boolean hasPermissionChecked = !role.getRmpPermissions().isEmpty();
		List<RmpPermissionGroup> groupList = rmpPermissionGroupRepository.findAll(new Sort(Direction.ASC, "code"));
		if (groupList != null && !groupList.isEmpty()) {
			role.setRmpPermssionsGroups(groupList);

			for (RmpPermissionGroup group : groupList) {
				group.getRmpPermissions();

				if (hasPermissionChecked) {
					for (RmpPermission permission : group.getRmpPermissions()) {
						Predicate p = new BeanPropertyValueEqualsPredicate("code", permission.getCode());
						if (!CollectionUtils.select(role.getRmpPermissions(), p).isEmpty()) {
							permission.setChecked(true);
						}
					}
				}
			}
		}
		sortGroupList(role.getRmpPermssionsGroups());

		// 设置人员
		boolean hasUserChecked = !role.getRmpUsers().isEmpty();
		List<RmpUser> userList = rmpUserRepository.findAll(new Sort(Direction.ASC, "code"));
		if (userList != null && !userList.isEmpty()) {
			role.setAllUsers(userList);
			if (hasUserChecked) {
				for (RmpUser user : userList) {
					user.getRmpDept();
					Predicate p = new BeanPropertyValueEqualsPredicate("code", user.getCode());
					if (!CollectionUtils.select(role.getRmpUsers(), p).isEmpty()) {
						user.setChecked(true);
					}
				}
			}
		}
		return role;
	}

	@Override
	public RmpRole save(RmpRole rmpRole, String[] permissions, String[] userCodes) {
		rmpRole.setRmpPermissions(new HashSet<RmpPermission>());
		if (permissions != null && permissions.length > 0) {
			for (String permission : permissions) {
				rmpRole.getRmpPermissions().add(rmpPermissionRepository.findOne(permission));
			}
		}
		rmpRole.setRmpUsers(new HashSet<RmpUser>());
		if (userCodes != null && userCodes.length > 0) {
			for (String userCode : userCodes) {
				rmpRole.getRmpUsers().add(rmpUserRepository.findOne(userCode));
			}
		}

		RmpRole newRmpRole = rmpRoleRepository.save(rmpRole);

		myShiroDbRealm.clearAllCachedAuthorizationInfo();

		return newRmpRole;
	}

	@Override
	public RmpRole update(RmpRole rmpRole, String[] permissions, String[] userCodes) {
		RmpRole role = rmpRoleRepository.findOne(rmpRole.getCode());
		role.setName(rmpRole.getName());
		role.setRemark(rmpRole.getRemark());

		role.setRmpPermissions(new HashSet<RmpPermission>());
		if (permissions != null && permissions.length > 0) {
			for (String permission : permissions) {
				role.getRmpPermissions().add(rmpPermissionRepository.findOne(permission));
			}
		}
		role.setRmpUsers(new HashSet<RmpUser>());
		if (userCodes != null && userCodes.length > 0) {
			for (String userCode : userCodes) {
				role.getRmpUsers().add(rmpUserRepository.findOne(userCode));
			}
		}
		RmpRole newRmpRole = rmpRoleRepository.update(role);
		myShiroDbRealm.clearAllCachedAuthorizationInfo();

		return newRmpRole;
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
	public List<RmpPermissionGroup> findRmpPermissionGroups() {
		List<RmpPermissionGroup> groupList = rmpPermissionGroupRepository.findAll(new Sort(Direction.ASC, "code"));
		if (groupList != null && !groupList.isEmpty()) {
			for (RmpPermissionGroup group : groupList) {
				group.getRmpPermissions();
			}
		}
		sortGroupList(groupList);
		return groupList;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void sortGroupList(List<RmpPermissionGroup> groupList) {
		Comparator typeCodeComparable = new ReverseComparator(new BeanComparator("rmpPermissionType.code"));
		if (groupList != null && !groupList.isEmpty()) {
			for (RmpPermissionGroup group : groupList) {
				Collections.sort(group.getRmpPermissions(), typeCodeComparable);
			}
		}
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.REQUIRED)
	public List<RmpUser> findRmpUsers() {
		List<RmpUser> userList = rmpUserRepository.findAll(new Sort(Direction.ASC, "code"));
		if (userList != null && !userList.isEmpty()) {
			for (RmpUser user : userList) {
				user.getRmpDept();
			}
		}
		return userList;
	}
}
